/* 
Scenic Graphics Library
Copyright (C) 2007 Jouni Tulkki

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USApackage scenic;
*/

#include <stdio.h>
#include <stdlib.h>

#include "common.h"


using namespace Scenic::Renderer;


//
// class ResourcePool
//

ResourcePool::ResourcePool(const char *name, bool debug)
{
	this->name = name;
	this->debug = debug;
	numItems = 0;
}

Resource *ResourcePool::get(int id)
{
	id--;
	if(id >= 0 && id < pool.size)
		return pool.data[id];
	return 0;
}

void ResourcePool::add(Resource *resource)
{
	Synchronized sync(this);

	int i;

	for(i = 0; i < pool.size; i++)
		if(!pool.data[i])
			goto found;

	pool.resize(pool.size + 1);
	i = pool.size - 1;
found:
	resource->id = i + 1;
	pool.data[i] = resource;

	numItems++;
	if(debug)
		printf("Pool %s has %d items\n", name, numItems);
}

void ResourcePool::remove(Resource *resource)
{
	Synchronized sync(this);

	for(int i = 0; i < pool.size; i++)
	{
		if(pool.data[i] == resource)
		{
			pool.data[i] = 0;
			break;
		}
	}
	numItems--;
	if(debug)
		printf("Pool %s has %d items\n", name, numItems);
}

//
// class JNIEnvPtr
//

JNIEnvPtr::JNIEnvPtr(JavaVM *vm)
{
	this->vm = vm;
	if(vm->GetEnv((void**)&env, JNI_VERSION_1_4) == JNI_EDETACHED)
	{
		vm->AttachCurrentThread((void**)&env, NULL);
		detach = true;
	}
	else
	{
		detach = false;
	}
}

JNIEnvPtr::~JNIEnvPtr()
{
	if(detach)
	{
		vm->DetachCurrentThread();
	}
}

//
// class Resource
//

Resource::Resource(ResourcePool *pool)
{
	debug = 0xdbdbdbdb;
	refCount = 1;
	javaObject = 0;
	javaObjectRefCount = 0;
	javaVm = 0;

	this->pool = pool;
	pool->add(this);
}

Resource::~Resource()
{
	if(debug != 0xdbdbdbdb)
		printf("Resource::~Resource: debug = %X pool=%s\n", debug, pool->name);
	pool->remove(this);
	if(javaObjectRefCount > 0)
	{
		fprintf(stderr, "Resource::~Resource - javaObjectRefCount > 0\n");
		while(javaObjectRefCount > 0)
			releaseReference();
	} 
	debug = 0xfeeefeee;
}

void Resource::release()
{
	if(debug != 0xdbdbdbdb)
	{
		printf("Resource::release: debug = %X pool=%s\n", debug, pool->name);
		char *a = 0;
		*a = 0;
	}
	refCount--;
	if(refCount == 0)
	{
		delete this;
	}
}

void Resource::addReference(JNIEnv *env, jobject object)
{
	JavaVM *vm;

	env->GetJavaVM(&vm);
	addReference(vm, object);
}

void Resource::addReference(JavaVM *vm, jobject object)
{
	Synchronized sync(this);

	if(javaObjectRefCount == 0)
	{
		javaVm = vm;

		JNIEnvPtr env(javaVm);

		javaObject = env->NewGlobalRef(object);
		javaObjectRefCount++;
	}
}

void Resource::releaseReference()
{
	Synchronized sync(this);

	javaObjectRefCount--;
	if(javaObjectRefCount == 0)
	{
		JNIEnvPtr env(javaVm);
		jobject obj = javaObject;

		javaObject = NULL;			// For thread safety
		env->DeleteGlobalRef(obj);
	}
}
